package com.zeratul.common.event.core.apply.publish;


import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import com.zeratul.common.core.context.DataContextHolde;
import com.zeratul.common.core.utils.spring.SpringUtils;
import com.zeratul.common.event.base.BasePublishServer;
import com.zeratul.common.event.domain.ZtEvent;
import com.zeratul.common.event.enums.Qos;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;

import java.util.Date;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 事件发布工具类 - 生产者调用
 * author Ken
 * create_time 2022/9/17
 */
@Slf4j
public class ZtEventPublish {

    /**
     * 服务层发布者对象
     */
    private static final BasePublishServer BASE_PUBLISH_SERVER;

    static {
        BASE_PUBLISH_SERVER = SpringUtils.getBean(BasePublishServer.class);
        if (ObjectUtil.isNull(BASE_PUBLISH_SERVER)) {
            log.warn("【事件总线】未找到发布者对象...");
        }
    }

    /**
     * 发送迅捷消息 - 不保证可靠性 性能最高 实时性最好
     * @param topic 事件主题
     * @param data 消息内容
     */
    public static <T> void sendQuickly(String topic, T data){
        send(topic, data, Qos.LOW, null);
    }

    /**
     * 发送可靠消息 - 保证消息可达 性能和实时性会略差
     * @param topic 事件主题
     * @param data 消息内容
     */
    public static <T> void sendReliable(String topic, T data){
        send(topic, data, Qos.HIGH, null);
    }

    /**
     * 发送延迟消息
     * @param topic 事件主题
     * @param data 消息内容
     * @param time 延迟事件
     * @param unit 时间单位
     */
    public static <T> void sendDelay(String topic, T data, Qos qos, long time, TimeUnit unit){
        send(topic, data, qos, unit.toMillis(time));
    }

    /**
     * 统一的发送方法
     */
    public static <T> void send(String topic, T data, Qos qos, Long delayTimeMs){
        send(topic, data, qos, delayTimeMs, null);
    }

    /**
     * 统一的发送方法
     */
    public static <T> void send(String topic, T data, Qos qos, Long delayTimeMs, Map<String, Object> extra){
        //构建一个ZtEvent对象
        ZtEvent<T> ztEvent = new ZtEvent<T>()
                .setId(IdUtil.fastUUID())
                .setTopic(topic)
                .setQos(qos)
                .setMsg(data)
                .setDelayTime(delayTimeMs)
                .setSendTime(new Date())
                .setExtra(extra);

        //调用事件发送方法
        send(ztEvent);
    }

    /**、
     * 发送消息对象
     */
    public static <T> void send(ZtEvent<T> ztEvent) {
        if (!ObjectUtil.isAllNotEmpty(ztEvent, BASE_PUBLISH_SERVER)) {
            return;
        }
        //将当前链路上下文数据设置到ztEvent中
        ztEvent.setTraceContext(DataContextHolde.getTraceContextOnCopy());
        //将MDC相关数据设置到ztEvent中
        ztEvent.setMdc(MDC.getCopyOfContextMap());
        //调用服务层将事件发出
        BASE_PUBLISH_SERVER.sendEvent(ztEvent);
    }
}
